home *** CD-ROM | disk | FTP | other *** search
/ CU Amiga Super CD-ROM 19 / CU Amiga Magazine's Super CD-ROM 19 (1998)(EMAP Images)(GB)[!][issue 1998-02].iso / CUCD / Programming / LEDA / source / src / graph_alg / _maxflow.c < prev    next >
Encoding:
C/C++ Source or Header  |  1994-11-16  |  5.5 KB  |  238 lines

  1. /*******************************************************************************
  2. +
  3. +  LEDA  3.1c
  4. +
  5. +
  6. +  _maxflow.c
  7. +
  8. +
  9. +  Copyright (c) 1994  by  Max-Planck-Institut fuer Informatik
  10. +  Im Stadtwald, 6600 Saarbruecken, FRG     
  11. +  All rights reserved.
  12. *******************************************************************************/
  13.  
  14.  
  15.  
  16.  
  17. #include <LEDA/graph_alg.h>
  18. #include <math.h>
  19.  
  20.  
  21. static void gt_bfs(node s_vert, int dist_s_vert, 
  22.                    const graph& G, node s, 
  23.                    const edge_array<num_type>& flow,
  24.                    const edge_array<num_type>& cap,
  25.                          node_data<int>& dist);
  26.  
  27.  
  28. num_type MAX_FLOW(graph& G, node s, node t, const edge_array<num_type>& cap, 
  29.                                                   edge_array<num_type>& flow)
  30. {
  31.  
  32. /* Computes a maximum flow from source s to sink t, using the
  33.    Goldberg-Tarjan algorithm [Journal ACM 35 (Oct 1988) p921-940].
  34.    ( Applies push steps to vertices with positive preflow, based on 
  35.      distance labels.  Uses FIFO rule (implemented by FIFO queue) 
  36.      for selecting a vertex with +ve preflow. )
  37.  
  38.    input:   cap[e]  gives capacity of edge e 
  39.  
  40.    output:  flow[e] flow on edge e
  41.             returns total flow into sink
  42.  
  43.    node_arrays used by the algorithm:
  44.    dist[v]   = lower bound on shortest distance from v to t
  45.    excess[v] = (total incoming preflow[v]) - (total outgoing preflow[v])
  46.  
  47.    Implemented by  Joseph Cheriyan & Stefan Naeher.
  48. */
  49.  
  50. node_data<int> dist(G,0);
  51.  
  52. node_array<num_type>  excess(G,0);
  53.  
  54. node_list U;   // FIFO Queue used for selecting vertex with positive preflow
  55. node v,w;
  56. edge e;
  57.  
  58. int N = G.number_of_nodes();
  59.  
  60. /*
  61.  heuristic: parameter for heuristic suggested by Goldberg to speed up algorithm 
  62.             compute exact distance labels after every "heuristic" relabel steps
  63.  
  64.             experiments indicate that sqrt(|E|) is a good choice  (S.N.)
  65. */
  66.  
  67. int heuristic = int(sqrt(G.number_of_edges()));
  68.  
  69. int limit_heur   = heuristic;
  70. int num_relabels = 0;
  71.  
  72. if (s == t) error_handler(1,"MAXFLOW: source == sink");
  73.  
  74. forall_edges(e,G) flow[e] = 0;
  75.  
  76. forall_out_edges(e,s) // saturate all edges leaving from s
  77. { v = target(e);
  78.   if (excess[v] == 0 && v!=s) U.append(v);
  79.   flow[e] = cap[e];
  80.   excess[v] += cap[e];
  81.  }
  82.  
  83. dist[s] = N;
  84.  
  85. while (! U.empty() )      /* main loop */
  86.   v = U.pop();
  87.  
  88.   if (v == t) continue;
  89.  
  90.   int dv = dist[v];
  91.  
  92.   num_type ev = excess[v];
  93.  
  94.   // push flow along each edge e = (v,w) in the residual graph with
  95.   // dist[v] == dist[w] + 1
  96.  
  97.   if (dv < N)
  98.    forall_out_edges(e,v)
  99.    { if (ev <= 0) break;
  100.      w = target(e);
  101.      if (dv == dist[w]+1)
  102.      { num_type delta = cap[e]-flow[e];
  103.        if (delta > 0)
  104.        { if (ev < delta) delta = ev;
  105.          if (excess[w] == 0) U.append(w);
  106.          flow[e] += delta;
  107.          excess[w] += delta;
  108.          ev -= delta;
  109.         }
  110.       }
  111.     }
  112.  
  113.   forall_in_edges(e,v)
  114.   { if (ev <= 0) break;
  115.     w = source(e);
  116.     if (dv == dist[w]+1)
  117.     { num_type delta = flow[e];
  118.       if (delta > 0)
  119.       { if (ev < delta) delta = ev;
  120.         if (excess[w] == 0 && w != s ) U.append(w);
  121.         flow[e] -= delta;
  122.         excess[w] += delta;
  123.         ev -= delta;
  124.        }
  125.      }
  126.  
  127.     } 
  128.  
  129.   excess[v] = ev;
  130.   
  131.   if (ev > 0)
  132.   {
  133.     // relabel vertex v (i.e. update dist[v]) because all
  134.     // admissible edges in the residual graph have been saturated 
  135.  
  136.     num_relabels++;
  137.   
  138.     if (heuristic && (num_relabels == limit_heur))
  139.       { 
  140.         // heuristic suggested by Goldberg to reduce number of relabels:
  141.         // periodically compute exact dist[] labels by two backward bfs 
  142.         // one starting at t and another starting at s
  143.  
  144.         limit_heur += heuristic;
  145.  
  146.        node x;
  147.        forall_nodes(x,G) dist[x] = MAXINT;
  148.  
  149.        gt_bfs(t,0,G,s,flow,cap,dist);
  150.        gt_bfs(s,N,G,s,flow,cap,dist);
  151.       }
  152.     else
  153.       { 
  154.         int min_dist = MAXINT;
  155.  
  156.         forall_out_edges(e,v)
  157.           if (cap[e] > flow[e] && dist[v] < N)
  158.             //pushes towards s that increase flow[e] are not allowed
  159.             min_dist = Min(min_dist,dist[target(e)]);
  160.  
  161.         forall_in_edges(e,v)
  162.           if (flow[e] > 0)
  163.             min_dist = Min(min_dist,dist[source(e)]);
  164.  
  165.         if (min_dist != MAXINT) min_dist++;
  166.         dist[v] = min_dist;
  167.        }
  168.  
  169.     if (! U.member(v) ) U.push(v);    
  170.      
  171.   } // if (excess[v] > 0)
  172.  
  173. }  // while (!U.empty())  
  174.        
  175.    
  176.  
  177. /*
  178. // code to verify that flow is legal
  179. num_type total_s_cap = 0;
  180. forall_out_edges(e,s)  total_s_cap += cap[e];
  181. if (total_s_cap != (excess[s] + excess[t]))
  182.    error_handler(999,"gt_max_flow: total out cap s != excess[s] + excess[t]");
  183. */
  184.  
  185. return excess[t];  // value of maximum flow from s to t
  186.   
  187. }
  188.  
  189.  
  190.  
  191.  
  192. //procedure to perform backward bfs starting at vertex s_vert with 
  193. //distance label dist_s_vert
  194.  
  195. static
  196. void gt_bfs(node s_vert, 
  197.             int dist_s_vert, 
  198.             const graph& G, 
  199.             node s, 
  200.             const edge_array<num_type>& flow,
  201.             const edge_array<num_type>& cap, 
  202.             node_data<int>& dist)
  203.   node_queue Q;
  204.  
  205.   Q.append(s_vert);
  206.   dist[s_vert] = dist_s_vert;
  207.  
  208.   while (! Q.empty() )
  209.   { 
  210.     node x = Q.pop();
  211.     int  d = dist[x] + 1;
  212.  
  213.     edge e;
  214.     forall_out_edges(e,x)
  215.     { node y = target(e); 
  216.       if (flow[e] > 0 && dist[y] == MAXINT) // use only edges with positive flow
  217.       { dist[y] = d;
  218.         Q.append(y);
  219.         if (y == s) dist[y] = G.number_of_nodes();
  220.        }
  221.      }
  222.  
  223.     forall_in_edges(e,x)
  224.     { node y = source(e); 
  225.       if (cap[e] > flow[e] && dist[y] == MAXINT &&  s_vert != s)
  226.       { dist[y] = d;
  227.         Q.append(y);
  228.         if (y == s) dist[y] = G.number_of_nodes();
  229.        }
  230.      }
  231.  
  232.    } // while Q not empty
  233. }
  234.  
  235.